﻿using System;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Data;
using System.ComponentModel;
using Cqrs.Infrastructure.Database;
using Cqrs.Infrastructure.Aggregate;
using System.Reflection;
using Cqrs.StateMachineDesigner.CustomCode;
using Ninject;
using System.Collections.Generic;
using System.IO;

namespace Cqrs.StateMachineDesigner.Database
{
    /// <summary>
    /// Interaction logic for AggregateList.xaml
    /// </summary>
    public partial class AggregateList : Window
    {
        private Guid _guid;
        private string _assemblyLocation;
        private Type _domainType;
        private string _smfFile;
        private string _dbLocation;
        private DataGrid _datagrid;

        public AggregateList()
        {
            InitializeComponent();
        }

        public Guid DisplayAggregates(Type domainType, string assemblyLocation, string smfFile, string dbLocation)
        {
            if (!Directory.Exists(dbLocation))
                throw new ArgumentException(string.Format("The DB Location {0} does not exist.", dbLocation));

            this.Title = string.Format("Aggregates for: {0}", domainType.AssemblyQualifiedName);
            _assemblyLocation = assemblyLocation;
            _domainType = domainType;
            _dbLocation = dbLocation;
            _smfFile = smfFile;
            RefreshGrid();
            this.ShowDialog();
            return _guid;
        }

        private void LoadSpinner()
        {
            _datagrid = (DataGrid)grdContent.Children[0];
            ContentControl cont = new ContentControl();
            cont.Content = new TextBlock() { Text = "Loading State Machines..." };
            cont.Style = (Style)grdContent.FindResource("LoadingSpinner");
            grdContent.Children.Clear();
            grdContent.Children.Add(cont);
        }

        private void RefreshGrid()
        {
            
            _datagrid = (DataGrid)grdContent.Children[0];
            Spinner.Load(grdContent, "Loading State Machines...");

            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            if (bw.IsBusy != true)
            {
                bw.RunWorkerAsync(_domainType);
            }

        }

        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                e.Result = EventStoreInstance
                                .Instance
                                .GetAggregateRoots((Type)e.Argument);
            }
            catch (Exception ex)
            {
                MessageBox.Show(EventStoreInstance.HandleEventStoreError(ex));
            }
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

            try
            {
                this.grdAggregates.ItemsSource = (IList<AggregateRootModel>)e.Result;
                grdContent.Children.Clear();
                grdContent.Children.Add(_datagrid);
            }
            catch (Exception ex)
            {
                // todo - show inner exception.
                MessageBox.Show(ex.Message);
            }
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private void btnOK_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (grdAggregates.SelectedItem == null) return;
                Select();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void grdAggregates_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            try
            {
                if (grdAggregates.SelectedItem == null) return;
                Select();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void Select()
        {
            if (grdAggregates.SelectedItem == null)
                return;

            _guid = ((AggregateRootModel)grdAggregates.SelectedItem).Id;
            this.Close();
        }

        private void grdAggregates_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            try
            {
                if (grdAggregates.SelectedItem == null)
                    return;

                Guid aggregateId = ((AggregateRootModel)grdAggregates.SelectedItem).Id;
                string typeName = ((AggregateRootModel)grdAggregates.SelectedItem).Type;
                DomainProperties domainProps = new DomainProperties(aggregateId, typeName);

                txtDomain.Text = "Loading Domain Object...";
                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork += new DoWorkEventHandler(GetDomainObject);
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(GetDomainObject_Completed);
                if (bw.IsBusy != true)
                {
                    bw.RunWorkerAsync(domainProps);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void GetDomainObject(object sender, DoWorkEventArgs e)
        {
            try
            {

                Assembly assembly = Assembly.LoadFrom(_assemblyLocation);
                DomainProperties domainProps = (DomainProperties)e.Argument;
                Guid aggregateId = domainProps.DomainId;
                string typeName = domainProps.TypeName;
                Type aggregateType = assembly.GetTypes().Where(p => p.AssemblyQualifiedName == typeName).First();
                AggregateRootWithState aggregateRoot = AggregateRootWithState.Load(aggregateType, _smfFile);

                aggregateRoot.LoadsFromHistory(
                    EventStoreInstance.Instance
                    .GetEventsForAggregate(aggregateId, assembly));

                e.Result = ObjectDumper.Write(aggregateRoot, 2);
            }
            catch (Exception ex)
            {
                e.Result = EventStoreInstance.HandleEventStoreError(ex);
            }
        }


        public void GetDomainObject_Completed(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                txtDomain.Text = (string)e.Result;
            }
            catch
            {
            }
        }

        private struct DomainProperties
        {
            public DomainProperties(Guid domainId, string typeName)
                : this()
            {
                DomainId = domainId;
                TypeName = typeName;
            }
            public Guid DomainId { get; private set; }
            public string TypeName { get; private set; }
        }
    }
}
